﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Yunwei.Web.SinalR
{
    public class SocketSingleton
    {
        private volatile static SocketSingleton _instance = null;
        private static readonly object lockHelper = new object();

        private Socket socketServer;
        private Dictionary<string, Socket> socketDict;
        private Dictionary<string, Thread> threadDict;

        private SocketSingleton()
        {
            socketDict = new Dictionary<string, Socket>();
            threadDict = new Dictionary<string, Thread>();
        }
        public static SocketSingleton CreateInstance()
        {
            if (_instance == null)
            {
                lock (lockHelper)
                {
                    if (_instance == null)
                    {
                        _instance = new SocketSingleton();
                        _instance.startListening();
                    }
                }
            }
            return _instance;
        }

        private void startListening()
        {
            IPHostEntry ipHost = Dns.GetHostEntry("www.yunwei.com");
            IPEndPoint ipEndPoint = new IPEndPoint(ipHost.AddressList[0], 9999);

            socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socketServer.Bind(ipEndPoint);

            socketServer.Listen(10);

            Thread thread = new Thread(watchConnecting);
            thread.IsBackground = true;
            thread.Start();
        }

        private void watchConnecting()
        {
            while (true)
            {
                Socket socketClient = socketServer.Accept();

                socketDict.Add(socketClient.RemoteEndPoint.ToString(), socketClient);
                socketClient.Send(Encoding.UTF8.GetBytes("客户端已连接"));

                Thread threadRecv = new Thread(receivMessage);
                threadRecv.IsBackground = true;
                threadRecv.Start(socketClient);

                threadDict.Add(socketClient.RemoteEndPoint.ToString(), threadRecv);
            }
        }

        private void receivMessage(object socketConnection)
        {
            try
            {
                Socket socketClient = socketConnection as Socket;
                while (socketClient.Connected)
                {
                    try
                    {
                        if (socketClient.Connected)
                        {
                            byte[] byteMessage = new byte[1024 * 1024 * 2];
                            int length = -1;

                            length = socketClient.Receive(byteMessage);

                            string message = Encoding.UTF8.GetString(byteMessage);
                            //do something
                            socketClient.Send(Encoding.UTF8.GetBytes(socketClient.RemoteEndPoint.ToString()));
                        }
                        else
                        {
                        }
                    }
                    catch (Exception ex)
                    {
                        socketDict.Remove(socketClient.RemoteEndPoint.ToString());
                        threadDict.Remove(socketClient.RemoteEndPoint.ToString());
                    }
                }

                socketDict.Remove(socketClient.RemoteEndPoint.ToString());
                threadDict.Remove(socketClient.RemoteEndPoint.ToString());
            }
            catch(Exception ex)
            {
            }
        }

        public void Send(string client, string message)
        {
            try
            {
                foreach (var key in socketDict.Keys)
                {
                    Socket socket = socketDict[key];
                    if (socket != null && socket.Connected)
                        socket.Send(Encoding.UTF8.GetBytes(message));
                }
            }

            catch (Exception ex)
            {
                socketDict.Remove(client);
                threadDict.Remove(client);
                Console.WriteLine("客户端失去链接");
            }
        }

        public void Close()
        {
            try
            {
                socketServer.Shutdown(SocketShutdown.Both);
                Thread.Sleep(100);
                socketServer.Close();

                foreach(var socket in socketDict)
                {
                    socket.Value.Shutdown(SocketShutdown.Both);
                    Thread.Sleep(10);
                    socket.Value.Close();
                }

                socketServer.Dispose();
                socketServer = null;
            }
            catch (Exception ex)
            {
            }
            finally
            {
            }
        }
    }
}
